// =============================================================================
//  STATS - Statistical Analysis Tools, v.0.01
//  Copyright (C) 2012  Marco Vettigli
// -----------------------------------------------------------------------------
//
// This program  is free software:  you can  redistribute it and/or  modify it
// under the terms of the  GNU General Public License as published by the Free
// Software Foundation,  either version 3 of the License,  or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY;  without even  the  implied  warranty  of  MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License  for
// more details.
//
// You  should  have received a copy of the  GNU General Public License  along
// with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// == module ===================================================================
//
// MAINWINDOW.CPP
// The class MainWindow is the main window of StatS graphical user interface.
//
// Author: Marco Vettigli
//
// The class defines the main window for StatS application. It is composed by
// a menu bar, tool bar and status bar by default. Furthermore it contains a
// QTreeWidget for managing currently opened widgets and a QTabWidget as
// working area.
//
// == implementation ===========================================================
//
// TODO: write MainWindow implementation documentation
//
// =============================================================================

// == include directives =======================================================

#include <QTreeWidgetItem>
#include <QInputDialog>
#include <QFileDialog>
#include <QMessageBox>
#include <QFont>
#include <QMenu>
#include <QDebug>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "core/stablewidget.h"
#include "core/utils.h"
#include "core/sscatterplot.h"
#include "gui/dialogimportcsv.h"

using namespace StatS;

// == constructors and destructors =============================================

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //newTableWidget();
    // -------------------------------------------------------------------------
    // for debug only
    // -------------------------------------------------------------------------
    StatS::STable* table = StatS::Utils::parseStatS(
                "/home/marco/projects/1122FSZ_2.stats");
    _tables.append(table);
    openTableWidget(table);
    // -------------------------------------------------------------------------

}

MainWindow::~MainWindow()
{
    delete ui;
}

// == getters ==================================================================

// == setters ==================================================================

// == inspectors ===============================================================

// == accessor function definitions ============================================

StatS::STable* MainWindow::newTableWidget()
{
    // initialize STableWidget and underling STable
    StatS::STableWidget* tableWidget = new StatS::STableWidget(ui->mainTab);
    StatS::STable* table = tableWidget->table();
    table->setName(QString("Untitled%1").arg(_untitledNumber));
    _untitledNumber++;
    _tables.append(table);
    // add STableWidget to tabWidget and append reference to STable
    ui->mainTab->addTab(tableWidget, QIcon(":/images/table"), table->name());
    ui->mainTab->setCurrentWidget(tableWidget);
    return table;
}

StatS::STable* MainWindow::openTableWidget(StatS::STable* table)
{
    // check if table reference is null
    if (table == 0) return false;
    // check if table is already opened
    if (getTableWidget(table) != 0) return false;
    // initialize STableWidget
    StatS::STableWidget* tableWidget
            = new StatS::STableWidget(ui->mainTab, table);
    // add STableWidget to tabWidget
    ui->mainTab->addTab(tableWidget, QIcon(":/images/table"), table->name());
    ui->mainTab->setCurrentWidget(tableWidget);
    // update windows list and return
    return table;
}

StatS::STable * MainWindow::getTable(const QString name)
{
    StatS::STable* table = 0;
    // find selected table
    for (int i = 0; i < _tables.size(); i++)
        if (_tables.at(i)->name() == name) {
            table = _tables.at(i);
            break;
        }
    return table;
}

StatS::STable * MainWindow::getCurrentTable()
{
    StatS::STableWidget* widget = dynamic_cast<StatS::STableWidget*>(
                ui->mainTab->currentWidget());
    if (widget !=0 ) return widget->table();
    else return 0;
}

StatS::STable * MainWindow::getSelectedTable()
{
    StatS::STable* table = getTable(ui->mainTree->currentItem()->text(0));
    return table;
}

int MainWindow::getTableWidgetIndex(const QString name)
{
    for(int i = 0; i < ui->mainTab->count(); i++) {
        if (ui->mainTab->tabText(i) == name) return i;
    }
    // table name not found
    return -1;
}

StatS::STableWidget* MainWindow::getTableWidget(StatS::STable* table)
{
    // get reference to currently selected table
    if (!table) table = getCurrentTable();
    // browse mainTab widgets looking for the one associated with table
    for (int i = 0; i < ui->mainTab->count(); i++) {
        StatS::STableWidget* tableWidget
                = dynamic_cast<StatS::STableWidget*>(ui->mainTab->widget(i));
        if (tableWidget !=0 && tableWidget->table() == table)
            return tableWidget;
    }
    // STable not found
    return 0;
}

void MainWindow::updateTablesList()
{
    QFont open_font = QFont();
    QFont closed_font = QFont();
    open_font.setBold(true);

    ui->mainTree->clear();

    foreach(StatS::STable* table, _tables) {
        // set list item name and icon based on object properties
        QTreeWidgetItem* item = new QTreeWidgetItem(ui->mainTree);
        item->setText(0, table->name());
        item->setIcon(0, QIcon(":/images/table"));
        // set list item font if table is open or closed
        if (getTableWidget(table)) item->setFont(0, open_font);
        else item->setFont(0, closed_font);
        // add list item
        ui->mainTree->addTopLevelItem(item);
    }
}

// == static variables =========================================================

int MainWindow::_untitledNumber = 1;

// == static funtion definitions ===============================================

// == private function definitions =============================================

void MainWindow::on_mainTab_tabCloseRequested(int index)
{
    // delete STableWidget and return
    delete ui->mainTab->widget(index);
    return;
}

void MainWindow::on_mainTree_doubleClicked(const QModelIndex& /*index*/)
{
    // get selected table and check if it exists
    StatS::STable* table = getSelectedTable();
    if (table == 0) return;
    // check if QTableWidget associated with table is present
    if (getTableWidget(table)) return;
    // open the QTableWidget
    openTableWidget(table);
    return;
}

void MainWindow::on_mainTree_customContextMenuRequested(const QPoint &pos)
{
    // check if user selected a table
    if (ui->mainTree->itemAt(pos) == 0) return;
    // create context menu
    QMenu* contextMenu = new QMenu(ui->mainTree);
    contextMenu->addAction("Change name", this,
                           SLOT(on_actionChange_name_triggered()));
    contextMenu->addSeparator();
    contextMenu->addAction("Save", this, SLOT(on_actionSave_triggered()));
    contextMenu->addAction("Close", this, SLOT(on_actionClose_triggered()));
    contextMenu->exec(ui->mainTree->mapToGlobal(pos));
}

void MainWindow::on_mainTab_currentChanged(int /*index*/)
{
    updateTablesList();
    // check if there is no QTableWidget opened
    if (ui->mainTab->count() == 0) {
        ui->actionClose->setDisabled(true);
        ui->actionSave->setDisabled(true);
    } else {
        ui->actionClose->setEnabled(true);
        ui->actionSave->setEnabled(true);
    }
}

// == actions handlers =========================================================

void MainWindow::on_actionExit_triggered()
{
    this->close();
}

void MainWindow::on_actionNew_triggered()
{
    newTableWidget();
}

void MainWindow::on_actionOpen_triggered()
{
    // get the file to open
    QFileDialog* dialog = new QFileDialog(this);
    dialog->setFilter("StatS data file (*.stats)");
    dialog->setWindowTitle("Open table");
    dialog->setAcceptMode(QFileDialog::AcceptOpen);
    if (dialog->exec() == QFileDialog::Accepted) {
        StatS::STable* table = StatS::Utils::parseStatS(
                    dialog->selectedFiles().at(0));
        if (table == 0 || getTable(table->name())) {
            QMessageBox::critical(this, "Table couldn't be opened",
                                  "The table cannot be opened because of a \n"
                                  "parsing error or because the file is not\n"
                                  "available.", QMessageBox::Ok);
            delete dialog;
            return;
        }
        // open the table
        _tables.append(table);
        openTableWidget(table);
    }
    delete dialog;
}

void MainWindow::on_actionSave_triggered()
{
    // get current table
    StatS::STable* current = 0;
    QObject* senderParent = ((QAction*)this->sender())->parent();
    if (senderParent == this) current = getCurrentTable();
    else current = getSelectedTable();
    if (current == 0) return;
    // check if table file is present
    if (current->fileName().isEmpty()) {
        // get the file to be saved
        QFileDialog* dialog = new QFileDialog(this);
        dialog->setFilter("StatS data file (*.stats)");
        dialog->setWindowTitle("Save as");
        dialog->setConfirmOverwrite(true);
        dialog->setAcceptMode(QFileDialog::AcceptSave);
        dialog->selectFile(QString("%1.stats").arg(current->name()));
        if (dialog->exec() == QFileDialog::Accepted)
            current->setFilename(dialog->selectedFiles().at(0));
        else return;
        delete dialog;
    }
    // save table content
    if (!current->save()) QMessageBox::critical(
                this, "Table not saved", "Because of an internal error\n"
                "the table could not be saved.");
    return;
}

void MainWindow::on_actionClose_triggered()
{
    // get current table
    StatS::STable* current = 0;
    QObject* senderParent = ((QAction*)this->sender())->parent();
    if (senderParent == this) current = getCurrentTable();
    else current = getSelectedTable();
    if (current == 0) return;
    // check if table content are saved
    if (!current->isDataSaved()) on_actionSave_triggered();
    // TODO: close any widget bound to table
    // delete STableWidget and table
    _tables.removeOne(current);
    delete getTableWidget(current);
    delete current;
    updateTablesList();
}

void MainWindow::on_actionChange_name_triggered()
{
    // get current table
    StatS::STable* current = 0;
    QObject* senderParent = ((QAction*)this->sender())->parent();
    if (senderParent == this) current = getCurrentTable();
    else current = getSelectedTable();
    if (current == 0) return;
    // ask to user a new valid name
    QString newName = QInputDialog::getText(this, "Change table name",
                                    "Enter new table name", QLineEdit::Normal,
                                     current->name());
    if (newName.isEmpty()) return;
    if (getTable(newName)) {
        QMessageBox::warning(this, "Couldn't rename table",
                             "The table couldn't be renamed\n"
                             "because new name is not valid.",
                             QMessageBox::Ok);
        return;
    }
    // change table name both on STable and opened tab
    int index = getTableWidgetIndex(current->name());
    if (index != -1) ui->mainTab->setTabText(index, newName);
    current->setName(newName);
    // update table list and return
    updateTablesList();
    return;
}

void MainWindow::on_actionCut_triggered()
{
    StatS::STableWidget* widget = getTableWidget();
    if (widget) widget->cutSelection();
    else return;
}

void MainWindow::on_actionCopy_triggered()
{
    StatS::STableWidget* widget = getTableWidget();
    if (widget) widget->copySelection();
    else return;
}

void MainWindow::on_actionPaste_triggered()
{
    StatS::STableWidget* widget = getTableWidget();
    if (widget) widget->pasteClipboard();
    else return;
}

void MainWindow::on_actionClear_triggered()
{
    StatS::STableWidget* widget = getTableWidget();
    if (widget) widget->clearSelection();
    else return;
}

void MainWindow::on_actionImport_csv_triggered()
{
    // define new dialog
    DialogImportCsv* dialog = new DialogImportCsv(this);
    if (dialog->exec() == QDialog::Accepted) {
        // initialize STableWidget and underling STable
        StatS::STable* table = StatS::Utils::parseCsv(
                    dialog->getFileName(),
                    dialog->getSeparatorChar(),
                    dialog->getQuoteChar(),
                    dialog->isFirstColumnNames());
        if (table == 0) {
            QMessageBox::critical(this, "Parsing error",
                                  "It was not possible to construct a table "
                                  "because of data inconsistency.",
                                  QMessageBox::Ok);
            return;
        }
        _tables.append(table);
        openTableWidget(table);
    }
}

void MainWindow::on_actionScatter_Plot_triggered()
{
    StatS::SScatterPlot* d = new StatS::SScatterPlot(ui->mainTab);
    d->setLinkedTable(getCurrentTable());
    d->setDataSources((SDoubles*)getCurrentTable()->getColumnReference(37),
                      (SDoubles*)getCurrentTable()->getColumnReference(40));
    ui->mainTab->addTab(d, "ScatterPlot");
}
